前面寫到 producing code 完成了工作,並呼叫 resolve
或 reject
送出結果,接下來 consuming code 可以利用 promise 的 then
、catch
、finally
等方法進行後續。
語法:
promise.then(
function(result) { /* 處理成功的結果 */ },
function(error) { /* 處理錯誤 */ }
);
then
可以傳入兩個 callback 參數,第一個會在 promise 狀態變為 fulfilled 時執行並接收結果;第二個 (非必要) 則是 rejected 時執行接收錯誤。
// fulfilled 的情況
let promise = new Promise(function(resolve, reject) {
setTimeout(() => resolve('done!'), 1000);
});
// 執行第一個 callback
promise.then(
result => alert(result), // 一秒後顯示 'done!'
error => alert(error) // 不執行
);
// rejected 的情況
let promise = new Promise(function(resolve, reject) {
setTimeout(() => reject(new Error('Whoops!')), 1000);
});
// 執行第二個 callback
promise.then(
result => alert(result), // 不執行
error => alert(error) // 一秒後顯示 'Error: Whoops!'
);
如果 then
只處理成功情況可以只寫第一個參數,只處理錯誤可以第一個參數寫成 null,如 .then(null, errorHandlingFunction)
或者採用下方 catch 的寫法。
使用 catch(f)
跟上述的 .then(null, f)
是一樣的意思:
let promise = new Promise((resolve, reject) => {
setTimeout(() => reject(new Error('Whoops!')), 1000);
});
promise.catch(alert); // 一秒後顯示 'Error: Whoops!'
finally
方法同樣是傳入 callback 函式,它和 then
相似的地方在於只要 promise 有結果 (settled),無論成功失敗,finally
中的函式都會執行。finally
的用意是做整個任務的最終總整理 (cleanup/ finalizing),例如停止 loading 狀態或中斷不用的連結。就像一個活動結束後,無論是失敗或成功都要清理善後。
new Promise((resolve, reject) => {
setTimeout(() => resolve('value'), 2000);
})
.finally(() => alert('Promise ready')) // 無論結果如何都先執行
.then(result => alert(result)); // 'value'
從例子中可以看出 finally
的一些特性還有和 then
的差異:
finally
中的函式沒有參數。finally
不用來處理結果,也不知道 promise 成功與否,它只是做 promise 結束後都要做的事。finally
先執行,但後面的 then
仍然印出結果,也就是 promise 結果會直接「穿過」 finally
到後面對應的處理函式。也因此 finally
不一定要擺在最後呼叫。finally
不應回傳東西,硬要回傳也會被忽略。例外是當它丟出錯誤或回傳一個 rejected promise 時,會將這個錯誤 (而非原本的結果) 傳給後面的錯誤處理函式。(嚴格來說例子中的箭頭函式就是有回傳,個人不喜歡這種寫法,但先保留。)promise 的狀態為 'pending' 時,then
、catch
、finally
方法會等待它的結果。
如果 promise 已經 settled,then
、catch
、finally
則會立刻執行,但並不影響結果。
let promise = new Promise(resolve => resolve('done!'));
promise.then(alert); // done!
這個例子中 executor 同步呼叫了 resolve
,promise 在建立時就會立刻 settled,但並不影響後面才加上處理函式。換句話說,處理函式可以在任何時候加上,如果已經有結果就會馬上執行,這樣的特性也讓 promise 更有彈性。